package com.guessdroid.sensing;
import java.util.List;


import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
import android.net.wifi.ScanResult;


// reusable multi-sensor recorder of raw data
public class Measurement implements SensorEventListener{
	
	private RawData data;
	private long beginTime;
	private volatile AudioFlag audioThreadFlag = AudioFlag.Stopped; 
	private Keeper keeper;
	private boolean listening= false;
	
	public Measurement(Keeper details){
		this.keeper=details;
	}
	
	public void start() // start collecting data
	{
		data=new RawData();
		data.wifiData=doWifiScan();
		beginTime=System.nanoTime();
		keeper.micBuffer.startRecording();
		audioThreadFlag=AudioFlag.Recording;
		startAudioReaderThread();
	    keeper.mSensorManager.registerListener(this, keeper.mLight, SensorManager.SENSOR_DELAY_FASTEST);
	    keeper.mSensorManager.registerListener(this, keeper.mAcc, SensorManager.SENSOR_DELAY_FASTEST);
	    listening = true;
	}
	
	private void startAudioReaderThread(){
		new Thread(new Runnable() {
	        public void run() {
	        	short[] isData= new short[keeper.aReadSize()];
	            while (audioThreadFlag == AudioFlag.Recording)
	            {
	            	int got=keeper.micBuffer.read(isData,0,isData.length);
	            	short[] newData=new short[got];
	            	System.arraycopy(isData, 0, newData, 0, got);
	            	data.auStamps.add(getTimeStamp());
	            	data.auData.add(newData);
	            }
	            audioThreadFlag=AudioFlag.Stopped;
	            keeper.micBuffer.stop();
	        }	        
	    }).start();
	}
	
	// no pause option. let's assume user does not start doing random things while measuring
	// and other pauses will not be noticeable for UI, so they should be short-timed enough.
	// stop collecting data, return data and reset state
	public RawData stopAndGetData() 
	{
		keeper.mSensorManager.unregisterListener(this);
		listening = false;
		if (audioThreadFlag!=AudioFlag.Stopped) {
			audioThreadFlag=AudioFlag.StopRecording;
			while (audioThreadFlag!=AudioFlag.Stopped) {} // waits until thread ends
		} 
		keeper.resetAudio();
		RawData ret=data;
		data=null;
		return ret;
	}
	
	public void onAccuracyChanged(Sensor sensor, int accuracy) {} // for some reason 2 changes occur

	// light event occurs on change, others periodically
	public void onSensorChanged(SensorEvent event) {
		try{
			Sensor sensor = event.sensor;
	        if (sensor.getType() == Sensor.TYPE_LIGHT) {
				data.lightData.add(event.values[0]);
				data.lightStamps.add(getTimeStamp());
	        }
	        else if(sensor.getType()== Sensor.TYPE_ACCELEROMETER){
	        	if(listening){
		        	data.accData.add(event.values[0]);
		        	//data.accData.add(event.values[1]); //these were redundant
		        	//data.accData.add(event.values[2]);
		        	data.accStamps.add(getTimeStamp());
	        	}
	        }
        }catch (Exception ex){        	
        	throw new RuntimeException("Error in onSensorChanged", ex);
        }
        
	}
	
	private List<ScanResult> doWifiScan() {
		if(!keeper.mWifiManager.isWifiEnabled()) {return null;}
		keeper.mWifiManager.startScan();
		return keeper.mWifiManager.getScanResults();
	}
	
	private int getTimeStamp()
	{
		//todo. think OF later. can add that if no other problems
		long tDiff=System.nanoTime()-beginTime;
		// if (nano<begin) {OF}
		return (int)(tDiff>>19); // can detect ~1ms changes, will loop once in ~12 days
	}
	
	private enum AudioFlag{
		Recording,
		StopRecording, 
		Stopped,
	}
}


